﻿//-------------------------------------------------------------------
//	Copyright (c) 2012 Fedotov I.V.
//	All rights reserved.
//-------------------------------------------------------------------
/*
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program. If not, see http://www.gnu.org/licenses/.

	Project SVN page 
*/

#if !defined(EventSender_h)
#define EventSender_h

#include "EventListener.h"
#include <vector>

using namespace std;

/*
using:

//Senders:
#define EVENT_SENDER1_MOUSE 1

class sender1:public EventSender<sender1>{

void somefunction(){
  fireEvent(this,EVENT_SENDER1_MOUSE);
}

};


#define EVENT_SENDER2_CLICK 1

class sender2:public EventSender<sender2>{

void somefunction(){
  fireEvent(this,EVENT_SENDER2_CLICK);
}

};

//Listener:
class recieveclass:public EventListener<sender1>,
                   public EventListener<sender2>{

sender1 s1;
sender2 s2;

recieveclass(){
  s1.addListener(this);
	s2.addListener(this);
}

void Event(sender1 *eventSender,int eventNum){
	  switch(eventNum){
      case EVENT_SENDER1_MOUSE:
        eventSender->...
	    break;
	  }
}
  
void Event(sender2 *eventSender,int eventNum){
    switch(eventNum){
      case EVENT_SENDER2_MOUSE:
        eventSender->...
	    break;
	  }
}

/----------------------------------------/

Or:
//Event base class

class event1:public EventSender<event1>{
public:
  int event_var1;
};

//Senders:
#define EVENT_SENDER1_MOUSE 1

class sender1:public event1{

void somefunction(){
  fireEvent(this,EVENT_SENDER1_MOUSE);
}

};


#define EVENT_SENDER2_CLICK 1

class sender2:public EventSender<sender2>{

void somefunction(){
  fireEvent(this,EVENT_SENDER2_CLICK);
}

};

//Listener:
class recieveclass:public EventListener<sender1>,
                   public EventListener<sender2>{

sender1 s1;
sender2 s2;

recieveclass(){
  s1.addListener(this);
	s2.addListener(this);
}

void Event(sender1 *eventSender,int eventNum){
	  switch(eventNum){
      case EVENT_SENDER1_MOUSE:
        eventSender->...
	    break;
	  }
}
  
void Event(sender2 *eventSender,int eventNum){
    switch(eventNum){
      case EVENT_SENDER2_MOUSE:
        eventSender->...
	    break;
	  }
}

*/

template<class TYPE> class EventSender{

	vector<EventListener<TYPE> *> ListenersList;
  vector<EventListener<TYPE> *> deletedListenersList;

public:

EventSender(){
	
}

~EventSender(){

}

void fireEvent(TYPE *sender,int eventNum){
	if(sender==NULL)return;

	//deleting event listeners
	vector<EventListener<TYPE> *>::iterator iter;
	vector<EventListener<TYPE> *>::iterator iterDeleted;
	if(!deletedListenersList.empty() && !ListenersList.empty()){
		for(iterDeleted=deletedListenersList.begin();iterDeleted!=deletedListenersList.end();iterDeleted++){
			for(iter=ListenersList.begin();iter!=ListenersList.end();iter++){
				if((*iterDeleted)==(*iter)){
					deletedListenersList.erase(iterDeleted);
					ListenersList.erase(iter);
				}
			}
		}
	}
	if(!deletedListenersList.empty()){
		deletedListenersList.clear();
	}

	//sending events
	if(!ListenersList.empty()){
		for(iter=ListenersList.begin();iter!=ListenersList.end();iter++){
			if((*iter)!=NULL){
				//checks than 'iter' was not deleted while firing
				if(!deletedListenersList.empty()){
					int findFlag=0;
	       	for(iterDeleted=deletedListenersList.begin();iterDeleted!=deletedListenersList.end();iterDeleted++){
						if((*iterDeleted)==(*iter)){
							findFlag=1;
						}
					}
					if(!findFlag)(*iter)->Event(sender,eventNum);
	      }
				else {
				  (*iter)->Event(sender,eventNum);
				}
			}
		}
	}
}


//ptrListener alloc and release out here
void addListener(EventListener<TYPE> *ptrListener){
	if(ptrListener!=NULL)ListenersList.push_back(ptrListener);
}

//no release ptr in list, only remove it at list
void removeListener(EventListener<TYPE> *ptrListener){
	if(ptrListener==NULL)return;
	deletedListenersList.push_back(ptrListener);
}


private:

};



#endif